package com.csyf.manager.channel.nmpay;

import org.apache.commons.lang3.StringUtils;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

public class MD5SignUtils {

	/** = */
	public static final String QSTRING_EQUAL = "=";
	/** & */
	public static final String QSTRING_SPLIT = "&";

	public static final String UTF8 = "UTF-8"; // 发往银联Upmp的字符串编码采用utf-8的编码方式

	/**
	 * 
	 * 1、加签<br>
	 * 2、…<br>
	 * 
	 * @param preSignStr
	 * @param mD5key
	 * @return
	 * @throws Exception
	 * @see
	 */
	public static String sign(String preSignStr, String mD5key) throws Exception {
		// 若返回域最后一域为空则会多出一个&符号，此时需要去掉
		if (preSignStr.endsWith(QSTRING_SPLIT)) {
			preSignStr = preSignStr.substring(0, preSignStr.length() - 1);
		}
		preSignStr = preSignStr + QSTRING_SPLIT + "key=" + mD5key;
		String sign = SHAUtil.SHA1Encode(preSignStr, UTF8).toUpperCase();
		return sign;
	}

	/**
	 * 签名
	 * 
	 * @author dev
	 * @param mD5key
	 * @param req
	 * @param md5Key
	 * @param logger
	 * @throws Exception
	 * @throws ChannelException
	 * @see
	 */
	public static String contentSign(String value, String mD5key) throws Exception {
		// 若返回域最后一域为空则会多出一个&符号，此时需要去掉
		if (value.endsWith(QSTRING_SPLIT)) {
			value = value.substring(0, value.length() - 1);
		}
		value = value + QSTRING_SPLIT + "key=" + mD5key;
		String sign = SHAUtil.SHA1Encode(value, UTF8).toUpperCase();

		return sign;
	}

	/**
	 * 把请求要素按照“参数=参数值”的模式用“&”字符拼接成字符串
	 * 
	 * @param para
	 *            请求要素
	 * @param sort
	 *            是否需要根据key值作升序排列
	 * @param encode
	 *            是否需要URL编码
	 * @return 拼接成的字符串 &参数1=参数值&参数2=参数值 2、签名原始串中，字段名和字段值都采用原始值，不进行URLEncode
	 * @throws UnsupportedEncodingException
	 */
	public static String createLinkString(Map<String, String> para, boolean encode) throws UnsupportedEncodingException {

		List<String> keys = new ArrayList<String>(para.keySet());
		Collections.sort(keys);// ascii码从小到大排序
		StringBuilder sb = new StringBuilder();// StringBuffer是线程安全类，但是在单线程情况下,StringBuilder性能更佳(非线程安全)
		for (int i = 0; i < keys.size(); i++) {
			String key = keys.get(i);
			String value = para.get(key).toString();
			if (StringUtils.isBlank(value)) {
				continue;// 空值不传递，不参与签名组串
			}
			value = value.trim();
			if (encode) {// 是否需要编码
				value = URLEncoder.encode(value, UTF8);
			}
			if (i == keys.size() - 1) {
				// 最后一个字串不加&
				sb.append(key).append(QSTRING_EQUAL).append(value);
			} else {
				sb.append(key).append(QSTRING_EQUAL).append(value).append(QSTRING_SPLIT);
			}
		}
		return sb.toString();
	}

	/**
	 * 同步请求参数验签
	 * 
	 * @author dev
	 * @param req
	 * @param md5Key
	 * @param logger
	 * @return
	 * @throws Exception
	 * @throws ChannelException
	 * @see
	 */
	public static boolean verfy(Map<String, String> reqMap, String md5Key) {

		boolean flag = false;

		try {
			String sign = reqMap.remove("sign").toString();

			String preVerfyStr = createLinkString(reqMap, false);
			// 若返回域最后一域为空则会多出一个&符号，此时需要去掉
			if (preVerfyStr.endsWith(QSTRING_SPLIT)) {
				preVerfyStr = preVerfyStr.substring(0, preVerfyStr.length() - 1);
			}

			preVerfyStr = preVerfyStr + QSTRING_SPLIT + "key=" + md5Key;
			String verfy = SHAUtil.SHA1Encode(preVerfyStr, UTF8).toUpperCase();

			if (sign.equals(verfy)) {
				flag = true;
			}
		} catch (Exception e) {
			return flag;
		}
		return flag;

	}

	/*
	 * 异步验签
	 */
	public static boolean verfyAsyn(String preVerfyStr, String sign, String md5Key) {

		boolean flag = false;

		try {
			// 若返回域最后一域为空则会多出一个&符号，此时需要去掉
			if (preVerfyStr.endsWith(QSTRING_SPLIT)) {
				preVerfyStr = preVerfyStr.substring(0, preVerfyStr.length() - 1);
			}

			preVerfyStr = preVerfyStr + QSTRING_SPLIT + "key=" + md5Key;
			String verfy = SHAUtil.SHA1Encode(preVerfyStr, UTF8).toUpperCase();

			if (sign.equals(verfy)) {
				flag = true;
			}
		} catch (Exception e) {
			return flag;
		}
		return flag;

	}

	/*
	 * 加签
	 */
	public static void signMap(Map<String, String> reqMap, String md5Key) {

		try {
			String preVerfyStr = createLinkString(reqMap, false);
			// 若返回域最后一域为空则会多出一个&符号，此时需要去掉
			if (preVerfyStr.endsWith(QSTRING_SPLIT)) {
				preVerfyStr = preVerfyStr.substring(0, preVerfyStr.length() - 1);
			}

			preVerfyStr = preVerfyStr + QSTRING_SPLIT + "key=" + md5Key;
			String sign = SHAUtil.SHA1Encode(preVerfyStr, UTF8).toUpperCase();
			reqMap.put("sign", sign);
		} catch (Exception e) {
			return;
		}

	}
}
